//----BEGIN LICENSE----//
/*****************************************************************\
** prevalentLite - sqlite3 persistence object library 
**
** Copyright (C) 2008 Philip R. Schuchardt
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
**
*****************************************************************/
//----END LICENSE----//

//Our includes
#include "plByteArray.h"
#include "plObject.h"
#include "plDatabase.h"

//std includes
#include <string.h>

/*!
  \class plByteArray plByteArray <plByteArray>
  \brief plByteArray is a database aware array of bytes eg a blob, in database terms.

  plByteArray is extremely useful for storing any generic data.
 A good example is saving and loading images data, movie data, compressed data, etc...
You must first convert your data into a char* and find out how many bytes your storing.

 Make sure plByteArray::Setup() is called before using the class.
Without calling plByteArray::Setup(), the database doesn't know how to get or commit data

For example:
\code

class A {

A() {
    CreateObject();

    test.Setup("TestVar", this)

    //Note
    double doubleData[5];
    someData[0] = 1;
    someData[1] = 2;
    someData[2] = 3;
    someData[4] = 4;
    someData[5] = 5;

    int size = sizeof(double) * 5;
    char* charData = const_cast<char*>(someData);

    //This commit the charData to the database as a blob
    //Since this is commiting raw bytes, there my be portiblity issues, depending on your data
    test.SetData(charData, size);
}

~A() {
    DeleteObject();
}

privite:
    plByteArray test;

};

  */

//!Constructor
plByteArray::plByteArray() : plData() {
    Value = NULL;
    SizeInBytes = 0;
    Cached = false;
    OwnData = false;
}

//Constructor
plByteArray::plByteArray(char* value, int size) : plData() {
    Value = value;
    SizeInBytes = size;
    Disabled = true;
    OwnData = false;
}

//!Copy constructor
plByteArray::plByteArray(const plByteArray& obj) : plData() {
    Copy(obj);
}

//! Gets the data, Also see Size() to get the size of the data
const char* plByteArray::Data() {
    plData::GetData();
    return Value;
}

//Deletes the data
plByteArray::~plByteArray() {
    if(OwnData && Value) {
        delete[] Value;
    }
}

/*!
 Commits the value to the database.

Makes a depth copies Value data.  This object is resposible for
deleting that deap copy. This will not add \0 an the end of the string

\param value - The value that will be saved
\param size - The size (in bytes) of the value
*/
void plByteArray::SetData(const char* value, int size) {

    if(OwnData && Value) {
        delete[] Value;
    }

    //Copy the data
    Value = new char[size];
    memcpy(Value, value, size);

    //We own the data
    OwnData = true;

    SizeInBytes = size;
    plData::SetData();
}

/*!
  This make a copy of just the pointer of value.  This class doesn't take resposiblity
  for the deletion of value

  \param value - The ptr that this class will use
  \param size - The size of data in bytes of value
  */
void plByteArray::SetRawData(char* value, int size) {

    if(OwnData && Value) {
        delete[] Value;
    }

    //We don't own the data
    OwnData = false;

    Value = value;
    SizeInBytes = size;
    plData::SetData();
}


/*!
    Gets of the data in bytes

    May extract all the data from the database if the data isn't cached in memory

    \return The size in bytes of the data. Return 0 if no data
    */
int plByteArray::Size() {
    if(!Cached) {
        plData::GetData();
    }
    return SizeInBytes;
}


//!Copy constructor
void plByteArray::operator=(const plByteArray& obj) {
    Copy(obj);
}

//!Gets the data
plByteArray::operator const char*() {
    return Data();
}

//Binds the data with the statement
void plByteArray::Bind(sqlite3_stmt* statement, int index) const {
    sqlite3_bind_blob(statement, index, Value, SizeInBytes, SQLITE_TRANSIENT);
}

//Gets the data from the current statement
void plByteArray::Column(sqlite3_stmt* statement, int index) {
    SizeInBytes = sqlite3_column_bytes(statement, index);
    const void* tmp = sqlite3_column_blob(statement, index); //tmp is free shortly, so we need to copy it

    if(OwnData && Value) {
        delete[] Value;
    }

    Value = new char[SizeInBytes];
    memcpy(Value, tmp, SizeInBytes); //make the copy of the data
    OwnData = true;
}

//Does a smart copy of the object
void plByteArray::Copy(const plByteArray& obj) {
    SetData(obj.Value, obj.SizeInBytes); //Makes a depth copy
    Cached = obj.Cached;
    OwnData = obj.OwnData;
}

